package com.share.tool.mock.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.share.common.common.Page;
import com.share.common.utils.HttpUtil;
import com.share.common.utils.ThreadUtil;
import com.share.tool.mock.mapper.SourceDataMapper;
import com.share.tool.mock.model.db.HttpVariable;
import com.share.tool.mock.model.db.SourceConf;
import com.share.tool.mock.model.db.SourceData;
import com.share.tool.mock.model.dto.McParam;
import com.share.tool.mock.model.vo.SourceDataPageReq;
import com.share.tool.mock.service.HttpVariableService;
import com.share.tool.mock.service.ISourceConfService;
import com.share.tool.mock.service.ISourceDataService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 触发原始数据表  服务实现类
 * </p>
 *
 * @author author
 * @since 2023-11-24
 */
@Slf4j
@Service
public class SourceDataServiceImpl extends ServiceImpl<SourceDataMapper, SourceData> implements ISourceDataService {
    @Resource
    private SourceDataMapper sourceDataMapper;

    @Autowired
    private HttpVariableService mockHttpVariableService;

    @Autowired
    private ISourceConfService sourceConfService;

    @Override
    public Page pageList(SourceDataPageReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        LambdaQueryWrapper<SourceData> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(req.getResponse())) {
            queryWrapper.like(SourceData::getResponse, req.getResponse());
        }
        if (StringUtils.isNotBlank(req.getRequest())) {
            queryWrapper.like(SourceData::getRequest, req.getRequest());
        }
        queryWrapper.orderByDesc(SourceData::getBatchNo);
        List<SourceData> list = sourceDataMapper.selectList(queryWrapper);
        Page<SourceData> page = new Page<>(list, new PageInfo<>(list).getTotal(), req);
        for (SourceData item : list) {
            SourceConf byConfId = sourceConfService.getByConfId(item.getConfId());
            if (byConfId != null) {
                item.setStepSort(byConfId.getStepSort());
                item.setEventName(byConfId.getEventName());
                item.setStepName(byConfId.getStepName());
            }
        }

        //排序
        list = list.stream().sorted(Comparator.comparing(SourceData::getBatchNo).reversed().thenComparing(SourceData::getStepSort)).collect(Collectors.toList());
        page.setPageList(list);
        return page;
    }

    //生产数据-并执行请求
    @Override
    public Object trigerByConfId(Long id) {
        SourceConf sourceConf = sourceConfService.getByConfId(id);
        if (sourceConf == null) {
            throw new RuntimeException("sourceConf未找到配置,");
        }

        //生成数据
        String mockCode = sourceConf.getStepCode();//获取接口的code
        HttpVariable mockHttp = mockHttpVariableService.getByCode(mockCode);

        McParam mcParam = new McParam(new JSONObject());
        Object reObj = mockHttpVariableService.httpMock(mockHttp, mcParam);
        String str = reObj == null ? null : reObj.toString();

        //保存到数据库
        SourceData record = new SourceData();
        record.setRequest(str);
        record.setCreateTime(new Date());
        record.setBatchNo(System.currentTimeMillis());
        record.setConfId(id);
        record.setStepSort(sourceConf.getStepSort());
        sourceDataMapper.insert(record);

        //发起http请求
        Object result = requestService(sourceConf, record);
        return result;
    }

    //执行一个已经存在了的请求
    @Override
    public Object trigerByDataId(String id) {
        SourceData sourceData = sourceDataMapper.selectById(id);
        if (sourceData == null) {
            throw new RuntimeException("id对应的数据找不到");
        }
        SourceConf sourceConf = sourceConfService.getByConfId(sourceData.getConfId());
        Object result = requestService(sourceConf, sourceData);
        return result;
    }

    //发起http请求
    private String requestService(SourceConf sourceConf, SourceData sourceData) {
        String result = null;
        String exeStatus = "1";
        String errMsg = null;
        String url = sourceConf.getApiUrl();
        try {
            String param = sourceData.getRequest();
            String method = sourceConf.getMethod();
            if (method == null) {
                method = "post";
            }
            if (method.equalsIgnoreCase("get")) {
                Map<String, Object> tmpParam = JSON.parseObject(param, Map.class);
                log.info("即发起{}请求,url={},param={}", method, url, JSON.toJSONString(tmpParam));
                result = HttpUtil.get(url, tmpParam);
            } else {
                // 默认为json
                String contentType = sourceConf.getReqContentType();
                if (contentType == null) {
                    contentType = "json";
                }

                if (contentType.equalsIgnoreCase("form")) {
                    Map<String, Object> tmpParam = JSON.parseObject(param, Map.class);
                    log.info("即发起{}请求,contentType={},url={},param={}", method, contentType, url, JSON.toJSONString(tmpParam));
                    result = HttpUtil.postForm(url, JSON.parseObject(param, Map.class), null);
                } else if (contentType.contains("json")) {
                    log.info("即发起{}请求,contentType={},url={},param={}", method, contentType, url, param);
                    result = HttpUtil.post(url, param);
                }
            }
        } catch (Exception e) {
            errMsg = e.getMessage();
            exeStatus = "2";
            log.error("发起请求异常url={}", url, e);
        }

        //更新数据库状态
        updateSourceDataById(sourceData.getId(), result, errMsg, exeStatus);

        return result;
    }

    private void updateSourceDataById(long id, String response, String errMsg, String exeStatus) {
        SourceData record = new SourceData();
        record.setResponse(response);
        record.setId(id);
        record.setErrMsg(errMsg);
        record.setExeStatus(exeStatus);
        ThreadUtil.execute(() -> sourceDataMapper.updateById(record));
    }

    //生成数据并插入到datasource表中
    @Override
    public Object producerSourceData() {
        Map<String, List<SourceConf>> eventMap = sourceConfService.getEventMap();
        Collection<List<SourceConf>> events = eventMap.values();
        for (List<SourceConf> stepList : events) {
            if (CollectionUtils.isEmpty(stepList)) {
                continue;
            }

            long batch = System.currentTimeMillis();
            stepList = stepList.stream().sorted(Comparator.comparing(SourceConf::getStepSort)).collect(Collectors.toList());
            if (stepList.size() == 0 || !"1".equals(stepList.get(0).getOpenProducer())) {
                //如果有多条,以第一条的配置为准
                continue;
            }

            McParam mcParam = new McParam(new JSONObject());
            for (SourceConf step : stepList) {
                String mockCode = step.getMockCode();//获取接口的code
                HttpVariable mockHttp = mockHttpVariableService.getByCode(mockCode);
                if (mockHttp == null) {
                    continue;
                }
                Object reObj = mockHttpVariableService.httpMock(mockHttp, mcParam);
                String str = reObj == null ? null : reObj.toString();

                // 保存数据
                saveSourceData(step, batch, str);
            }
        }
        return null;
    }

    //消费数据
    @Override
    public Object consumerSourceData() {
        Map<String, List<SourceConf>> eventMap = sourceConfService.getEventMap();
        Collection<List<SourceConf>> events = eventMap.values();
        for (List<SourceConf> stepList : events) {
            if (CollectionUtils.isEmpty(stepList)) {
                continue;
            }

            //开启了消费,且地址存在
            stepList = stepList.stream().filter(e -> "1".equals(e.getOpenConsumer()) && StringUtils.isNotBlank(e.getApiUrl())).sorted(Comparator.comparing(SourceConf::getStepSort)).collect(Collectors.toList());
            if (stepList.size() == 0) {
                continue;
            }

            for (SourceConf sourceConf : stepList) {
                LambdaQueryWrapper<SourceData> queryWrapper = new LambdaQueryWrapper();
                queryWrapper.eq(SourceData::getConfId, sourceConf.getId());
                queryWrapper.eq(SourceData::getExeStatus, 0);//待执行
                queryWrapper.eq(SourceData::getStatus, 1);//数据有效的
                queryWrapper.last("limit 10");
                List<SourceData> sourceDataList = sourceDataMapper.selectList(queryWrapper);
                for (SourceData sourceData : sourceDataList) {
                    String result = requestService(sourceConf, sourceData);
                }
            }
        }
        return null;
    }

    private void saveSourceData(SourceConf step, long batch, String str) {
        SourceData record = new SourceData();
        record.setCreateTime(new Date());
        record.setConfId(step.getId());
        record.setBatchNo(batch);
        record.setRequest(str);
        record.setStatus("1");
        record.setExeStatus("0");
        sourceDataMapper.insert(record);
    }
}
